﻿Imports DotSpatial.Controls
Imports DotSpatial.Data
Imports DotSpatial.Symbology
Imports DotSpatial.Topology
Imports DotSpatial.Positioning
Imports System.Threading
Imports System.IO.Ports
Imports OpenTK.Graphics
Imports OpenTK.Graphics.OpenGL.GL
Imports System.Globalization






Public Class MainForm


    Dim Opengl As OGL = New OGL
    Dim revSalidaSensor As Double = 0.0
    Dim flagIsOcupadoCV As Boolean = False 'bandera para conocer el estado del CV, false = libre. true= ocupado
    Dim ultimaDosisObjetivo As Double = 1000 'Inicializar en 1000 para diferenciar el primer registro
    Dim rotacionSalidaCalculada As Double = 0
    Dim relacionTransmisionCalculada As Double = 0
    Dim porcentajeCvCalculado As Double = 0
    Dim dosisObjetivo As Double = 0
    Public flagRT As Boolean = True
    Dim flagDosisFija As Boolean = False
    Public Shared vectorCambio(100) As Double






    Public Property myCoordenateGPS As Coordinate = Nothing
    Public Property gpsActivo As Boolean = False
    'Public Property ePaintEventArgs As System.Windows.Forms.PaintEventArgs = Nothing
    'devuelve el indice
    Private pLastCoordinateIndex As Integer = -1
    Private Property AsFeatureSet As FeatureSet = Nothing
    'flags
    Public flagPausa As Integer
    Public flagCargarMapa As Integer
    Public conectado As Boolean = False
    ' para el opentk
    Public loader As Boolean = False
    Public sw As Stopwatch = New Stopwatch()
    'habilito el heades
    Public nombreLogAplicacion As String = ""
    Public nombreLogCV As String = ""
    Public nombreLogFueraDelMapa As String = ""
    Dim nombreLogAplicacionDF As String = ""

    'streamwriter
    Dim archivoLogAplicacion As IO.StreamWriter = Nothing
    'Dim archivoLogCV As IO.StreamWriter = Nothing
    Dim archivoLogFueraDelMapa As IO.StreamWriter = Nothing
    Dim archivoLogAplicacionDF As IO.StreamWriter = Nothing

    Dim logDescripcionAplicacion As String = ""
    Dim logDescripcionCV As String = ""
    Dim logDescFueraDelMapa As String = ""
    Dim logDescripcionAplicacionDF As String = ""
    Dim flagLog As Boolean = False
    'declarar los puertosf de conexion y asociarlos con los eventos
    Dim WithEvents puertoSensorEntrada As SerialPort
    Dim WithEvents puertoSensorSalida As SerialPort
    Dim WithEvents puertoConexionCV As SerialPort
    'datos de sensores
    Public datoSensorSalida As Double = 0
    Public datoSensorEntrada As Double = 0
    Public datoPosicionCV As Double = 0
    Public datoMoviendoCV As Double = 0
    Public datoUltimoCambioCV As Double = 0

    Public vectorS(4) As Double
    Public mediaS As Double
    Public contadorS As Integer

    Public vectorE(4) As Double
    Public mediaE As Double
    Public contadorE As Integer
    'es para guardar el dosis aux
    Dim dosisaux As String = ""

    'flag Sensores
    Public isOcupadoCV As Boolean = False
    'para posicion PositionChanged
    Dim MyCoordinate As New Coordinate
    Dim gradoRumbo As Azimuth
    Dim fl As IMapFeatureLayer
    Dim iShape As Integer = -1
    Dim velocidad As DotSpatial.Positioning.Speed
    Dim extenFeature As DotSpatial.Data.Extent = New DotSpatial.Data.Extent

    Public Sub New()


        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Hook into GPS.NET's device detection events.  These events will report on
        ' any GPS devices which have been found, along with any problems encountered and reasons
        ' why a particular device could NOT be detected.
        AddHandler Devices.DeviceDetectionAttempted, AddressOf Devices_DeviceDetectionAttempted
        AddHandler Devices.DeviceDetectionAttemptFailed, AddressOf Devices_DeviceDetectionAttemptFailed
        AddHandler Devices.DeviceDetectionStarted, AddressOf Devices_DeviceDetectionStarted
        AddHandler Devices.DeviceDetectionCompleted, AddressOf Devices_DeviceDetectionCompleted
        AddHandler Devices.DeviceDetectionCanceled, AddressOf Devices_DeviceDetectionCanceled
        AddHandler Devices.DeviceDetected, AddressOf Devices_DeviceDetected
        AddHandler Devices.FixAcquired, AddressOf Devices_FixAcquired
        AddHandler Devices.FixLost, AddressOf Devices_FixLost

        'Manejar las excepciones
        AddHandler Application.ThreadException, AddressOf Application_ThreadException
        AddHandler AppDomain.CurrentDomain.UnhandledException, AddressOf CurrentDomain_UnhandledException
    End Sub
#Region "GPS Eventos de deteccion  "
    'Boton deteccion y conexion automatica 
    Public Sub deteccionAutoButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles deteccionAutoButton1.Click
        Devices.BeginDetection()
        ProgresoConexionDialog1.Show()
        createLog()

    End Sub
    'Ocurre cuando se hace una busqueda y se cancela la deteccion del dispositivo antes de finalizar
    Sub Devices_DeviceDetectionCanceled(ByVal sender As Object, ByVal e As EventArgs)
        BeginInvoke(New EventHandler(AddressOf DeviceDetectionCanceled), sender, e)
    End Sub
    Private Sub DeviceDetectionCanceled(ByVal sender As Object, ByVal e As EventArgs)
        'statusLabel.Text = "Deteccion de dispositivo cancelado!"
        'detectButton.Enabled = True
        'cancelDetectButton.Enabled = False
        ProgresoConexionDialog1.statusTextBox1.Text = "Deteccion de dispositivo cancelado!"
    End Sub
    'Ocurre cuando un dispositivo responde y transmite datos
    Sub Devices_DeviceDetected(ByVal sender As Object, ByVal e As DeviceEventArgs)
        BeginInvoke(New EventHandler(Of DeviceEventArgs)(AddressOf DeviceDetected), sender, e)
    End Sub
    Private Sub DeviceDetected(ByVal sender As Object, ByVal e As DeviceEventArgs)

        Dim item As ListViewItem
        For Each item In ProgresoConexionDialog1.devicesListView.Items
            If Object.ReferenceEquals(item.Tag, e.Device) Then
                item.SubItems(1).Text = "GPS DETECTADO"
                item.ImageIndex = 0
            End If
        Next
        ProgresoConexionDialog1.devicesListView.Refresh()
        statusConexionLabel.Text = "Gps detectado " + e.Device.Name
        ProgresoConexionDialog1.Close()
        TrabajarButton1.Enabled = True
    End Sub
    'Ocurre cuando el proceso de busqueda de dispositivos ha finalizado
    Sub Devices_DeviceDetectionCompleted(ByVal sender As Object, ByVal e As EventArgs)
        BeginInvoke(New EventHandler(AddressOf DeviceDetectionCompleted), sender, e)
    End Sub
    Private Sub DeviceDetectionCompleted(ByVal sender As Object, ByVal e As EventArgs)
        ProgresoConexionDialog1.statusTextBox1.Text = ("Deteccion de dispositivo completado.")
        ' detectButton.Enabled = True
        ' cancelDetectButton.Enabled = False

    End Sub
    '  Ocurre cuando el proceso de busqueda de dispositivos ha empezado
    Sub Devices_DeviceDetectionStarted(ByVal sender As Object, ByVal e As EventArgs)
        BeginInvoke(New EventHandler(AddressOf DeviceDetectionStarted), sender, e)
    End Sub
    Private Sub DeviceDetectionStarted(ByVal sender As Object, ByVal e As EventArgs)
        ProgresoConexionDialog1.statusTextBox1.Text = "Detectando dispositivos..."
        ProgresoConexionDialog1.devicesListView.Items.Clear()
        'detectButton.Enabled = False
        'cancelDetectButton.Enabled = True

    End Sub
    'Ocurre cuando un dispositivo transmite datos gps no reconocibles
    Sub Devices_DeviceDetectionAttemptFailed(ByVal sender As Object, ByVal e As DeviceDetectionExceptionEventArgs)
        BeginInvoke(New EventHandler(Of DeviceDetectionExceptionEventArgs)(AddressOf DeviceDetectionAttemptFailed), sender, e)
    End Sub
    Private Sub DeviceDetectionAttemptFailed(ByVal sender As Object, ByVal e As DeviceDetectionExceptionEventArgs)
        Dim item As ListViewItem
        For Each item In ProgresoConexionDialog1.devicesListView.Items
            If Object.ReferenceEquals(item.Tag, e.Device) Then
                item.SubItems(1).Text = e.Exception.Message
                item.ToolTipText = e.Exception.Message
                item.ImageIndex = 1
            End If
        Next item
        ProgresoConexionDialog1.devicesListView.Refresh()
    End Sub
    'Ocurre antes de que un dispositivo sea comprobado como un dispositivo GPS
    Sub Devices_DeviceDetectionAttempted(ByVal sender As Object, ByVal e As DeviceEventArgs)
        BeginInvoke(New EventHandler(Of DeviceEventArgs)(AddressOf DeviceDetectionAttempted), sender, e)
    End Sub
    Public Sub DeviceDetectionAttempted(ByVal sender As Object, ByVal e As DeviceEventArgs)
        'undetectButton.Enabled = True

        For Each existingItem As ListViewItem In ProgresoConexionDialog1.devicesListView.Items
            If Object.ReferenceEquals(existingItem.Tag, e.Device) Then
                existingItem.SubItems(1).Text = "Detectando..."
                Return
            End If
        Next

        Dim item As New ListViewItem
        item.Text = e.Device.Name
        item.ImageIndex = 2
        item.Tag = e.Device
        item.SubItems.Add(New ListViewItem.ListViewSubItem(item, "Detectando..."))
        ProgresoConexionDialog1.devicesListView.Items.Add(item)
        ProgresoConexionDialog1.devicesListView.Refresh()
    End Sub
    'Ocurre cuando un dispositivo es capaz de detectar su pocicion actual
    Sub Devices_FixAcquired(ByVal sender As Object, ByVal e As DeviceEventArgs)
        BeginInvoke(New EventHandler(AddressOf DeviceFixAcquired), sender, e)
    End Sub
    Private Sub DeviceFixAcquired(ByVal sender As Object, ByVal e As DeviceEventArgs)
        'qualityTextBox1.Text = "Fix, ya se puede calcular la posicion"
        'NmeaInterpreter1.f()
    End Sub
    'Ocurre cuando un dispositivo gps perdio el fix y no puede calcular su posicion actual
    Sub Devices_FixLost(ByVal sender As Object, ByVal e As DeviceEventArgs)
        BeginInvoke(New EventHandler(AddressOf DeviceFixLost), sender, e)
    End Sub
    Private Sub DeviceFixLost(ByVal sender As Object, ByVal e As DeviceEventArgs)
        'qualityTextBox1.Text = "Se perdio el fix, ya no se puede calcular la posicion"
    End Sub
#End Region
#Region "Eventos del  NmeaInterpreter "
    Private Sub nmeaInterpreter1_SpeedChanged(ByVal sender As Object, ByVal e As SpeedEventArgs) Handles NmeaInterpreter1.SpeedChanged
        BeginInvoke(New EventHandler(Of SpeedEventArgs)(AddressOf SpeedChanged), sender, e)
    End Sub
    Private Sub SpeedChanged(ByVal sender As Object, ByVal e As SpeedEventArgs)
        'speedTextBox.Text = e.Speed.ToKilometersPerHour.ToString()
        'speedLabel.Text = speedTextBox.Text
        If DifPorcentajeDosNumeros(Math.Round(e.Speed.ToKilometersPerHour.Value, 1), My.MySettings.Default.velocidadIdeal, 0) < 2 Then
            KmHrsVisualLabel3.ForeColor = Color.Green
        ElseIf Math.Round(e.Speed.ToKilometersPerHour.Value, 1) < My.MySettings.Default.velocidadMinima Then
            KmHrsVisualLabel3.ForeColor = Color.Red
        Else
            KmHrsVisualLabel3.ForeColor = Color.Black
        End If
        KmHrsVisualLabel3.Text = Math.Round(e.Speed.ToKilometersPerHour.Value, 1).ToString & " Km/h"
    End Sub

    Private Sub nmeaInterpreter1_BearingReceived(ByVal sender As Object, ByVal e As AzimuthEventArgs) Handles NmeaInterpreter1.BearingReceived
        BeginInvoke(New EventHandler(Of AzimuthEventArgs)(AddressOf BearingReceived), sender, e)
    End Sub
    Private Sub BearingReceived(ByVal sender As Object, ByVal e As AzimuthEventArgs)
        'bearingPublic = e.Azimuth
    End Sub

    Private Sub nmeaInterpreter1_BearingChanged(ByVal sender As Object, ByVal e As AzimuthEventArgs) Handles NmeaInterpreter1.BearingChanged
        BeginInvoke(New EventHandler(Of AzimuthEventArgs)(AddressOf BearingChanged), sender, e)
    End Sub

    Private Sub BearingChanged(ByVal sender As Object, ByVal e As AzimuthEventArgs)
        'bearingTextBox.Text = e.Azimuth.ToString()
        'bearingLabel.Text = bearingTextBox.Text
        'bearingPublic = e.Azimuth
    End Sub

    Private Sub nmeaInterpreter1_AltitudeChanged(ByVal sender As Object, ByVal e As DistanceEventArgs) Handles NmeaInterpreter1.AltitudeChanged
        BeginInvoke(New EventHandler(Of DistanceEventArgs)(AddressOf AltitudeChanged), sender, e)
    End Sub
    Private Sub AltitudeChanged(ByVal sender As Object, ByVal e As DistanceEventArgs)
        'altitudeTextBox.Text = e.Distance.ToString()
        'altitudeLabel.Text = altitudeTextBox.Text
    End Sub

    Private Sub nmeaInterpreter1_Paused(ByVal sender As Object, ByVal e As EventArgs) Handles NmeaInterpreter1.Paused
        BeginInvoke(New EventHandler(AddressOf Paused), sender, e)
    End Sub
    Private Sub Paused(ByVal sender As Object, ByVal e As EventArgs)
        TrabajarButton1.Image = My.Resources.play
        statusConexionLabel.Text = "Pausa"
        flagPausa = 1
        'pauseButton.Enabled = False
        'resumeButton.Enabled = True
        'statusLabel.Text = "Pausa."

    End Sub
    Private Sub Resumed(ByVal sender As Object, ByVal e As EventArgs)
        statusConexionLabel.Text = "Trabajo reanudado"
        TrabajarButton1.Image = My.Resources.tractor_verde
        'pauseButton.Enabled = True
        'resumeButton.Enabled = False
    End Sub
    Private Sub nmeaInterpreter1_Resumed(ByVal sender As Object, ByVal e As EventArgs) Handles NmeaInterpreter1.Resumed
        BeginInvoke(New EventHandler(AddressOf Resumed), sender, e)
    End Sub
    Private Sub nmeaInterpreter1_Starting(ByVal sender As Object, ByVal e As DeviceEventArgs) Handles NmeaInterpreter1.Starting
        BeginInvoke(New EventHandler(Of DeviceEventArgs)(AddressOf Starting), sender, e)
    End Sub
    Private Sub Starting(ByVal sender As Object, ByVal e As DeviceEventArgs)
        'statusLabel.Text = "Conectado a " + e.Device.Name + "..."
        statusConexionLabel.Text = "Conectado a " + e.Device.Name + "..."
        pararTrabajoButton1.Enabled = True
        deteccionAutoButton1.Enabled = False
    End Sub

    Private Sub nmeaInterpreter1_Started(ByVal sender As Object, ByVal e As EventArgs) Handles NmeaInterpreter1.Started
        BeginInvoke(New EventHandler(AddressOf Started), sender, e)
    End Sub
    Private Sub Started(ByVal sender As Object, ByVal e As EventArgs)
        'statusLabel.Text = "Conectado!  Esperando datos..."
        'sentenceListBox.Items.Clear()
        'startButton.Enabled = False
        'stopButton.Enabled = True
        'pauseButton.Enabled = True
        'resumeButton.Enabled = False
        'positionLabel.Text = Position.Empty.ToString()
        'speedLabel.Text = Speed.Empty.ToString()
        'bearingLabel.Text = Azimuth.Empty.ToString()
        'altitudeLabel.Text = Distance.Empty.ToString()
    End Sub

    Private Sub nmeaInterpreter1_Stopping(ByVal sender As Object, ByVal e As EventArgs) Handles NmeaInterpreter1.Stopping
        BeginInvoke(New EventHandler(AddressOf Stopping), sender, e)
    End Sub
    Private Sub Stopping(ByVal sender As Object, ByVal e As EventArgs)
        statusConexionLabel.Text = "Deteniendo..."
    End Sub

    Private Sub nmeaInterpreter1_Stopped(ByVal sender As Object, ByVal e As EventArgs) Handles NmeaInterpreter1.Stopped
        BeginInvoke(New EventHandler(AddressOf Stopped), sender, e)
    End Sub
    Private Sub Stopped(ByVal sender As Object, ByVal e As EventArgs)


        NmeaInterpreter1.Device.CancelDetection()
        closeLog()
        statusConexionLabel.Text = "Trabajo detenido"
        'Cuando para de interpretar las sentencias tambien debe cerrar la conexion y vaciar el cache de deteccion
        'Cancels detection and removes any cached information about the device. 
        'Use the BeginDetection() method to re-detect the device and re-add it to the device cache. 


        'statusLabel.Text = "Detenido."
        'startButton.Enabled = True
        'stopButton.Enabled = False
        'pauseButton.Enabled = False
        'resumeButton.Enabled = False
    End Sub
    'Ocurre cuando la calidad del fix ha cambiado
    Private Sub nmeaInterpreter1_FixQualityChanged(ByVal sender As Object, ByVal e As EventArgs) Handles NmeaInterpreter1.FixQualityChanged
        BeginInvoke(New EventHandler(AddressOf FixQualityChanged), sender, e)
    End Sub
    Private Sub FixQualityChanged(ByVal sender As Object, ByVal e As EventArgs)
        'qualityTextBox1.Text = "La calidad del fix ha cambiado."
        'MsgBox("La calidad del fix ha cambiado")
        'logGpsListBox1.Items.Add("La calidad del fix ha cambiado")
        'logGpsListBox1.Items.Add("Tolerancia en la precision detectado por el dispositivo (promedio): " + NmeaInterpreter1.FixPrecisionEstimate.Value.ToString())
        ' logGpsListBox1.Items.Add("Tolerancia en la precision detectado por el dispositivo (promedio): " + Fix())

    End Sub
    'Private Sub nmeaInterpreter1_SatellitesChanged(ByVal sender As Object, ByVal e As SatelliteListEventArgs) Handles NmeaInterpreter1.SatellitesChanged
    '    BeginInvoke(New EventHandler(Of SatelliteListEventArgs)(AddressOf SatellitesChanged), sender, e)
    'End Sub

    'Private Sub SatellitesChanged(ByVal sender As Object, ByVal e As SatelliteListEventArgs)
    '    Dim satellite As Satellite

    '    ' Update each satellite
    '    For Each satellite In e.Satellites
    '        Dim isSatelliteNew As Boolean = True

    '        ' Look through the existing list for matches
    '        Dim viewItem As ListViewItem
    '        For Each viewItem In CalibracionCV.satellitesListView.Items
    '            ' Each item's Tag property houses a Satellite object
    '            Dim existing As Satellite = CType(viewItem.Tag, Satellite)

    '            ' Do the ID's match?
    '            If existing.PseudorandomNumber.Equals(satellite.PseudorandomNumber) Then
    '                ' Yes. Update the listview columns
    '                viewItem.SubItems(2).Text = satellite.Azimuth.ToString()
    '                viewItem.SubItems(3).Text = satellite.Elevation.ToString()
    '                viewItem.SubItems(4).Text = satellite.SignalToNoiseRatio.ToString()
    '                isSatelliteNew = False
    '            End If
    '        Next

    '        ' If no existing satellite was found, then add a new one
    '        If isSatelliteNew Then
    '            ' Add a new column for this satellite
    '            Dim newItem As New ListViewItem(satellite.PseudorandomNumber.ToString())
    '            newItem.SubItems.Add(satellite.Name)
    '            newItem.SubItems.Add(satellite.Azimuth.ToString())
    '            newItem.SubItems.Add(satellite.Elevation.ToString())
    '            newItem.SubItems.Add(satellite.SignalToNoiseRatio.ToString())
    '            newItem.Tag = satellite
    '            CalibracionCV.satellitesListView.Items.Add(newItem)
    '        End If
    '    Next
    'End Sub

    Private Sub nmeaInterpreter1_PositionChanged(ByVal sender As Object, ByVal e As PositionEventArgs) Handles NmeaInterpreter1.PositionChanged
        BeginInvoke(New EventHandler(Of PositionEventArgs)(AddressOf PositionChanged), sender, e)
    End Sub

    Private Sub PositionChanged(ByVal sender As Object, ByVal e As PositionEventArgs)
        gpsActivo = True
        'obtengo la coordenada
        gradoRumbo = NmeaInterpreter1.Bearing
        velocidad = NmeaInterpreter1.Speed
        MyCoordinate.Y = e.Position.Latitude
        MyCoordinate.X = e.Position.Longitude
        myCoordenateGPS = MyCoordinate

        Opengl.Cordenadas(MyCoordinate.X, MyCoordinate.Y, gradoRumbo.DecimalDegrees)
        pocisionCursor.Text = "X: " & e.Position.Longitude.ToString & " Y: " & e.Position.Latitude.ToString


        iShape = CoordinatesInShapefile(MyCoordinate.X, MyCoordinate.Y)

        If (iShape <> -1) Then
            If My.MySettings.Default.dosisFijaCheck = True Then
                KryptonLabelDosis.Text = fl.DataSet.DataTable.Rows.Item(iShape).Item(My.MySettings.Default.sustituirDescripcion) & " Dosis Fija=" & My.MySettings.Default.dosisFijaValor.ToString
                'Dosis actual (real) 
                'DosisActual(velocidad)
                'log para dosis fija
                If flagLog = True Then
                    logDescripcionAplicacionDF = ""
                    logDescripcionAplicacionDF += DateTime.Now.ToString("dd-MM-yyyy") & "," & DateTime.Now.ToString("hh:mm:ss") & "," & e.Position.Latitude.DecimalDegrees.ToString & "," & e.Position.Longitude.DecimalDegrees.ToString & "," & gradoRumbo.DecimalDegrees.ToString & ","
                    logDescripcionAplicacionDF += "NO," & My.MySettings.Default.dosisFijaValor.ToString & ",150,"
                    logDescripcionAplicacionDF += velocidad.ToKilometersPerHour.Value.ToString & "," & My.MySettings.Default.anchoLabor.ToString & "," & datoSensorSalida.ToString & "," & datoPosicionCV.ToString
                    'escribir 
                    archivoLogAplicacionDF.WriteLine(logDescripcionAplicacionDF)
                End If
                If flagDosisFija = False Then
                    RealizarCambio(TablaDosisPorcentajeCv(My.MySettings.Default.dosisFijaValor))
                    flagDosisFija = True
                    'Debug.WriteLine("flag df true")
                End If
                'archivoLogAplicacionDF.WriteLine(logDescripcionAplicacionDF)
            Else
                'KryptonLabelDosis.Text = fl.DataSet.DataTable.Rows.Item(iShape).Item(My.MySettings.Default.sustituirDescripcion) & " " & fl.DataSet.DataTable.Rows.Item(iShape).Item(My.MySettings.Default.sustituirDosisKgHa).ToString
                KryptonLabelDosis.Text = "Dosis: " & fl.DataSet.DataTable.Rows.Item(iShape).Item(My.MySettings.Default.sustituirDosisKgHa).ToString
                'Dosis actual (real) 
                'DosisActual(velocidad)
                'log para dosis variable
                dosisaux = TablaDosisPorcentajeCv(fl.DataSet.DataTable.Rows.Item(iShape).Item(My.MySettings.Default.sustituirDosisKgHa)).ToString
                If ultimaDosisObjetivo <> fl.DataSet.DataTable.Rows.Item(iShape).Item(My.MySettings.Default.sustituirDosisKgHa) Then
                    RealizarCambio(dosisaux)
                    ultimaDosisObjetivo = fl.DataSet.DataTable.Rows.Item(iShape).Item(My.MySettings.Default.sustituirDosisKgHa)
                    ToolStripLabelCambio.Text = dosisaux
                    ToolStripLabelUltimoCambio.Text = ultimaDosisObjetivo
                End If
                logDescripcionAplicacion = ""
                logDescripcionAplicacion += DateTime.Now.ToString("dd-MM-yyyy") & "," & DateTime.Now.ToString("hh:mm:ss") & "," & e.Position.Latitude.DecimalDegrees.ToString & "," & e.Position.Longitude.DecimalDegrees.ToString & "," & gradoRumbo.DecimalDegrees.ToString & ","
                logDescripcionAplicacion += "SI," & fl.DataSet.DataTable.Rows.Item(iShape).Item(My.MySettings.Default.sustituirDosisKgHa).ToString & ",150,"
                logDescripcionAplicacion += velocidad.ToKilometersPerHour.Value.ToString & "," & My.MySettings.Default.anchoLabor.ToString & "," & TablaDosisPorcentajeCv(fl.DataSet.DataTable.Rows.Item(iShape).Item(My.MySettings.Default.sustituirDosisKgHa)) & ","
                logDescripcionAplicacion += datoSensorSalida.ToString & "," & dosisaux & "," & datoUltimoCambioCV.ToString & "," & ultimaDosisObjetivo.ToString
                If flagLog = True Then
                    archivoLogAplicacion.WriteLine(logDescripcionAplicacion)
                End If
            End If
        Else
            logDescFueraDelMapa = ""
            logDescFueraDelMapa += DateTime.Now.ToString("dd-MM-yyyy") & "," & DateTime.Now.ToString("hh:mm:ss") & "," & e.Position.Latitude.DecimalDegrees.ToString & "," & e.Position.Longitude.DecimalDegrees.ToString & ";" & gradoRumbo.DecimalDegrees.ToString
            archivoLogFueraDelMapa.WriteLine(logDescFueraDelMapa)
        End If

    End Sub

#Region "Calculos referentes al CV"
    Public Function CalculoPrincipalCV(ByVal dosisObjetivo As Double, ByVal velocidad As Speed)
        If velocidad.ToKilometersPerHour.Value > My.MySettings.Default.velocidadMinima Then 'Primero controlamos que la sembradora tenga una velocidad minima
            If dosisObjetivo <> ultimaDosisObjetivo Then 'si la ultima dosis es distinto dosis objetivo hacer los calculos
                ultimaDosisObjetivo = dosisObjetivo 'guardar la ultima dosis objetivo para comparar con el siguiente
                'Primero calculamos la rotacion de salida necesaria para una dosis objetivo
                'Solo una vez se devera calcular la rotacionSalidaNecesaria, a menos que cambie la DO
                'Si entra por este if es para realizar pequeñas correcciones
                rotacionSalidaCalculada = CalculoRotacionSalidaNecesaria(dosisObjetivo, velocidad.ToMetersPerSecond.Value)
                relacionTransmisionCalculada = CalculoRelacionDeTransmisionEnSal(datoSensorEntrada, rotacionSalidaCalculada)
                porcentajeCvCalculado = TablaRelacionTransmisionPorcentajeCV(relacionTransmisionCalculada)
                RealizarCambio(porcentajeCvCalculado)
            Else 'ultima DO es igual a DO, se pueden hacer correcciones menores
                'se puede comparar DO con DA y hacer correcciones minimas
            End If
        End If
        Return 0
    End Function
#End Region

#Region "Gestion del CV"
    ''' <summary>
    ''' Verificar la dosificacion actual(Real)
    ''' </summary>
    ''' <param name="VelocidadAvance">Velocidad del tractor</param>
    ''' <returns>Devuelve la dosificacion actual (Kg/ha)</returns>
    ''' <remarks></remarks>
    Public Function DosisActual(ByVal VelocidadAvance As Speed) As Double
        Dim DosisKgHa As Double = 0
        'Calcular= (RevSegundoSalidadDelEjeDosificador * KgDeFertilizantePorGiro) / (10000*AnchoTrabajo*VelAvance)
        DosisKgHa = (datoSensorSalida * My.MySettings.Default.kgPorRevolucion) / ((My.MySettings.Default.anchoLabor * VelocidadAvance.ToMetersPerSecond.Value) / 10000)
        Return DosisKgHa
    End Function
    ''' <summary>
    ''' Se encarga solo de realizar el cambio, antes se debe conocer el estado del CV, posicion, etc
    ''' </summary>
    ''' <param name="cambio">De 0 a 100, El porcentaje de cambio que se quiere</param>
    ''' <remarks></remarks>
    Public Sub RealizarCambio(ByVal cambio As String)
        If isOcupadoCV = False And puertoConexionCV IsNot Nothing Then
            puertoConexionCV.Write(cambio, 0, 3)
        Else
            'Debug.Write("CV Ocupado")
        End If
    End Sub
    'Consultar el estado del CV
    'Posibles estados: moviendo, libre
    Public Shared Function ConsultarEstadoCV()
        'Console.WriteLine(configuracionForm.comConexionCV.ReadLine())
        Return 0
    End Function
    ''' <summary>
    ''' Determinar la rotacion requerida despejando formula que calcula kg/ha
    ''' </summary>
    ''' <param name="DosisObjetivo">La dosis leida desde el mapa</param>
    ''' <param name="velocidadAvance">Velocidad de avance del tractor</param>
    ''' <returns>La velocidad de rotacion necesaria</returns>
    ''' <remarks></remarks>
    Public Shared Function CalculoRotacionSalidaNecesaria(ByVal dosisObjetivo As Double, ByVal velocidadAvance As Double) As Double
        'Establecer tiempo que tarda entre un cambio y otro, calcular el cambio en una velocidad de siembra ideal
        'Primero establecer la necesidad de rotacion desde la formula de calculo de kg/ha
        Dim resultado As Double = 0
        resultado = ((dosisObjetivo * My.MySettings.Default.anchoLabor * velocidadAvance) / My.MySettings.Default.kgPorRevolucion) / 10000
        Return resultado
    End Function
    ''' <summary>
    ''' Calcula la relacion de transmision entre la velocidad de entrada(desde el sensor)
    ''' y una velocidad deseada, calculada gracias a la funcion CalculoRotacionSalidaNecesaria.
    ''' Otra alternativa es tomar los datos de sensores EN SAL y calcular la RT actual
    ''' </summary>
    ''' <param name="EntradaRps">Desde el sensor</param>
    ''' <param name="SalidaRps">Calculada desde la funcion CalculoRotacionSalidaNecesaria</param>
    ''' <returns>Devuelve la relacion de transmision con un decimal</returns>
    ''' <remarks></remarks>
    Public Shared Function CalculoRelacionDeTransmisionEnSal(ByVal EntradaRps As Double, ByVal SalidaRps As Double) As Double
        Dim rt As Double = 0
        rt = Math.Round((SalidaRps / EntradaRps), 3)
        Return rt
    End Function
    ''' <summary>
    ''' Tabla de relacion de transmision-Porcentaje Cambio
    ''' Determina que RT es equivalente a un porcentaje de cambio
    ''' Ejemplo= Una relacion de transmision 4 es igual a 5%
    ''' </summary>
    ''' <param name="RelacionDeTransmison">La relacion de transmision que se quiere conocer en porcentaje de CV</param>
    ''' <returns>Devuelve el cambio en porcentaje</returns>
    ''' <remarks></remarks>
    Public Shared Function TablaRelacionTransmisionPorcentajeCV(ByVal RelacionDeTransmison As Double) As Double
        Dim PorcentajeCambio As String = ""
        Select Case RelacionDeTransmison
            Case 3 To 4 'La rt empieza en 3.3/1
                PorcentajeCambio = "005"
            Case 98 To 100 'La rt termina en 100/1
                PorcentajeCambio = "100"
        End Select
        Return PorcentajeCambio
    End Function
    'no esta en uso, solo como alternativa
    Public Shared Function TablaDosisPorcentajeCv(ByVal Dosis As Double) As String
        Dim Cambio As String = ""
        Select Case Dosis
            Case vectorCambio(0) To 500
                Cambio = "000"
            Case vectorCambio(1) To vectorCambio(0)
                Cambio = "001"
            Case vectorCambio(2) To vectorCambio(1)
                Cambio = "002"
            Case vectorCambio(3) To vectorCambio(2)
                Cambio = "003"
            Case vectorCambio(4) To vectorCambio(3)
                Cambio = "004"
            Case vectorCambio(5) To vectorCambio(4)
                Cambio = "005"
            Case vectorCambio(6) To vectorCambio(5)
                Cambio = "006"
            Case vectorCambio(7) To vectorCambio(6)
                Cambio = "007"
            Case vectorCambio(8) To vectorCambio(7)
                Cambio = "008"
            Case vectorCambio(9) To vectorCambio(8)
                Cambio = "009"
            Case vectorCambio(10) To vectorCambio(9)
                Cambio = "010"
            Case vectorCambio(11) To vectorCambio(10)
                Cambio = "011"
            Case vectorCambio(12) To vectorCambio(11)
                Cambio = "012"
            Case vectorCambio(13) To vectorCambio(12)
                Cambio = "013"
            Case vectorCambio(14) To vectorCambio(13)
                Cambio = "014"
            Case vectorCambio(15) To vectorCambio(14)
                Cambio = "015"
            Case vectorCambio(16) To vectorCambio(15)
                Cambio = "016"
            Case vectorCambio(17) To vectorCambio(16)
                Cambio = "017"
            Case vectorCambio(18) To vectorCambio(17)
                Cambio = "018"
            Case vectorCambio(19) To vectorCambio(18)
                Cambio = "019"
            Case vectorCambio(20) To vectorCambio(19)
                Cambio = "020"
            Case vectorCambio(21) To vectorCambio(20)
                Cambio = "021"
            Case vectorCambio(22) To vectorCambio(21)
                Cambio = "022"
            Case vectorCambio(23) To vectorCambio(22)
                Cambio = "023"
            Case vectorCambio(24) To vectorCambio(23)
                Cambio = "024"
            Case vectorCambio(25) To vectorCambio(24)
                Cambio = "025"
            Case vectorCambio(26) To vectorCambio(25)
                Cambio = "026"
            Case vectorCambio(27) To vectorCambio(26)
                Cambio = "027"
            Case vectorCambio(28) To vectorCambio(27)
                Cambio = "028"
            Case vectorCambio(29) To vectorCambio(28)
                Cambio = "029"
            Case vectorCambio(30) To vectorCambio(29)
                Cambio = "030"
            Case vectorCambio(31) To vectorCambio(30)
                Cambio = "031"
            Case vectorCambio(32) To vectorCambio(31)
                Cambio = "032"
            Case vectorCambio(33) To vectorCambio(32)
                Cambio = "033"
            Case vectorCambio(34) To vectorCambio(33)
                Cambio = "034"
            Case vectorCambio(35) To vectorCambio(34)
                Cambio = "035"
            Case vectorCambio(36) To vectorCambio(35)
                Cambio = "036"
            Case vectorCambio(37) To vectorCambio(36)
                Cambio = "037"
            Case vectorCambio(38) To vectorCambio(37)
                Cambio = "038"
            Case vectorCambio(39) To vectorCambio(38)
                Cambio = "039"
            Case vectorCambio(40) To vectorCambio(39)
                Cambio = "040"
            Case vectorCambio(41) To vectorCambio(40)
                Cambio = "041"
            Case vectorCambio(42) To vectorCambio(41)
                Cambio = "042"
            Case vectorCambio(43) To vectorCambio(42)
                Cambio = "043"
            Case vectorCambio(44) To vectorCambio(43)
                Cambio = "044"
            Case vectorCambio(45) To vectorCambio(44)
                Cambio = "045"
            Case vectorCambio(46) To vectorCambio(45)
                Cambio = "046"
            Case vectorCambio(47) To vectorCambio(46)
                Cambio = "047"
            Case vectorCambio(48) To vectorCambio(47)
                Cambio = "048"
            Case vectorCambio(49) To vectorCambio(48)
                Cambio = "049"
            Case vectorCambio(50) To vectorCambio(49)
                Cambio = "050"
            Case vectorCambio(51) To vectorCambio(50)
                Cambio = "051"
            Case vectorCambio(52) To vectorCambio(51)
                Cambio = "052"
            Case vectorCambio(53) To vectorCambio(52)
                Cambio = "053"
            Case vectorCambio(54) To vectorCambio(53)
                Cambio = "054"
            Case vectorCambio(55) To vectorCambio(54)
                Cambio = "055"
            Case vectorCambio(56) To vectorCambio(55)
                Cambio = "056"
            Case vectorCambio(57) To vectorCambio(56)
                Cambio = "057"
            Case vectorCambio(58) To vectorCambio(57)
                Cambio = "058"
            Case vectorCambio(59) To vectorCambio(58)
                Cambio = "059"
            Case vectorCambio(60) To vectorCambio(59)
                Cambio = "060"
            Case vectorCambio(61) To vectorCambio(60)
                Cambio = "061"
            Case vectorCambio(62) To vectorCambio(61)
                Cambio = "062"
            Case vectorCambio(63) To vectorCambio(62)
                Cambio = "063"
            Case vectorCambio(64) To vectorCambio(63)
                Cambio = "064"
            Case vectorCambio(65) To vectorCambio(64)
                Cambio = "065"
            Case vectorCambio(66) To vectorCambio(65)
                Cambio = "066"
            Case vectorCambio(67) To vectorCambio(66)
                Cambio = "067"
            Case vectorCambio(68) To vectorCambio(67)
                Cambio = "068"
            Case vectorCambio(69) To vectorCambio(68)
                Cambio = "069"
            Case vectorCambio(70) To vectorCambio(69)
                Cambio = "070"
            Case vectorCambio(71) To vectorCambio(70)
                Cambio = "071"
            Case vectorCambio(72) To vectorCambio(71)
                Cambio = "072"
            Case vectorCambio(73) To vectorCambio(72)
                Cambio = "073"
            Case vectorCambio(74) To vectorCambio(73)
                Cambio = "074"
            Case vectorCambio(75) To vectorCambio(74)
                Cambio = "075"
            Case vectorCambio(76) To vectorCambio(75)
                Cambio = "076"
            Case vectorCambio(77) To vectorCambio(76)
                Cambio = "077"
            Case vectorCambio(78) To vectorCambio(77)
                Cambio = "078"
            Case vectorCambio(79) To vectorCambio(78)
                Cambio = "079"
            Case vectorCambio(80) To vectorCambio(79)
                Cambio = "080"
            Case vectorCambio(81) To vectorCambio(80)
                Cambio = "081"
            Case vectorCambio(82) To vectorCambio(81)
                Cambio = "082"
            Case vectorCambio(83) To vectorCambio(82)
                Cambio = "083"
            Case vectorCambio(84) To vectorCambio(83)
                Cambio = "084"
            Case vectorCambio(85) To vectorCambio(84)
                Cambio = "085"
            Case vectorCambio(86) To vectorCambio(85)
                Cambio = "086"
            Case vectorCambio(87) To vectorCambio(86)
                Cambio = "087"
            Case vectorCambio(88) To vectorCambio(87)
                Cambio = "088"
            Case vectorCambio(89) To vectorCambio(88)
                Cambio = "089"
            Case vectorCambio(90) To vectorCambio(89)
                Cambio = "090"
            Case vectorCambio(91) To vectorCambio(90)
                Cambio = "091"
            Case vectorCambio(92) To vectorCambio(91)
                Cambio = "092"
            Case vectorCambio(93) To vectorCambio(92)
                Cambio = "093"
            Case vectorCambio(94) To vectorCambio(93)
                Cambio = "094"
            Case vectorCambio(95) To vectorCambio(94)
                Cambio = "095"
            Case vectorCambio(96) To vectorCambio(95)
                Cambio = "096"
            Case vectorCambio(97) To vectorCambio(96)
                Cambio = "097"
            Case vectorCambio(98) To vectorCambio(97)
                Cambio = "098"
            Case vectorCambio(99) To vectorCambio(98)
                Cambio = "099"
            Case vectorCambio(100) To vectorCambio(99)
                Cambio = "100"
        End Select

        Return Cambio
    End Function
    Public Function CalcularRotacionEjeDosificador()
        Return 0
    End Function

#End Region
#Region "Puertos y conexion con CV"
    'Filtrar datos invalidos y convertir a double el string de entrada
    Public Shared Function FiltroDatosSensorES(ByVal entrada As String) As Double
        Dim resultado As Double = 0
        Dim aux1 As String = ""
        Dim aux2 As String = ""
        Dim sPatternUnDigito As String = "^\d{1}.\d{2}\ Rps$" 'para x.xx Rps
        Dim sPatternDosDigitos As String = "^\d{2}.\d{2}\ Rps$" 'para xx.xx Rps
        'eliminar espacios en blanco
        aux1 = Replace(Trim(entrada), vbCr, "") 'Sacar espacios en blanco y substituir vbCr
        'digito de una cifra entera x.xx
        'If aux1.Length = 9 Then
        '    ' expresion(regular)
        '    'Nro mil para error
        '    If System.Text.RegularExpressions.Regex.IsMatch(aux1, sPatternDosDigitos) = True Then
        '        aux2 = Mid(aux1, 1, 5)
        '        resultado = Double.Parse(aux2, CultureInfo.InvariantCulture)
        '    Else
        '        resultado = 100
        '    End If
        'formato x.xx Rps
        If aux1.Length = 8 Then
            If System.Text.RegularExpressions.Regex.IsMatch(aux1, sPatternUnDigito) = True Then
                aux2 = Mid(aux1, 1, 4)
                resultado = Double.Parse(aux2, CultureInfo.InvariantCulture)
            Else
                resultado = 100
            End If
        Else
            resultado = 100
            'Console.WriteLine(aux1 + "no es un dato valido por su longitud")
        End If
        Return resultado
    End Function
    'Cundo se reciben los datos desde los sensores, estas funciones son las encargadas 
    'de recibirlas
    'Private Sub puertoEntrada_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles puertoSensorEntrada.DataReceived
    '    If puertoSensorEntrada.ReadLine.Length > 1 Then
    '        Dim aux1 As String = ""
    '        Dim aux2 As Double = 0
    '        Dim aux3 As Double = 0
    '        aux1 = puertoSensorEntrada.ReadLine()
    '        aux2 = FiltroDatosSensorES(aux1)
    '        If aux2.Equals(100.0) Then 'si hay error en la lectura
    '            'datos no validos
    '            'KryptonLabel2.Text = aux1
    '        Else
    '            If contadorE < 4 Then
    '                'acumular
    '                contadorE = contadorE + 1
    '                vectorE(contadorE) = aux2
    '            Else
    '                'media
    '                For i = 0 To vectorE.Length - 1
    '                    mediaE = mediaE + vectorE(i)
    '                Next
    '                mediaE = mediaE / vectorE.Length
    '                datoSensorEntrada = mediaE
    '                mediaE = 0
    '                contadorE = 0
    '                vectorE(0) = Nothing
    '                vectorE(1) = Nothing
    '                vectorE(2) = Nothing
    '                vectorE(3) = Nothing
    '                vectorE(4) = Nothing
    '            End If
    '            'datoSensorEntrada = aux2
    '            KryptonLabelEntrada.Text = datoSensorEntrada.ToString
    '            'ToolStripLabelSensorEntrada.Text = datoSensorEntrada.ToString
    '            If flagRT = True Then
    '                aux3 = datoSensorSalida
    '                logDescripcionRelTransmision = ""
    '                'con filtrado
    '                'logDescripcionRelTransmision += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & ";" & datoSensorEntrada.ToString & ";" & datoSensorSalida.ToString & ";" & CalculoRelacionDeTransmisionEnSal(datoSensorEntrada, aux3).ToString
    '                'sin filtrado
    '                logDescripcionRelTransmision += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & "," & aux2 & "," & datoSensorSalida.ToString & "," & CalculoRelacionDeTransmisionEnSal(aux2, datoSensorSalida).ToString

    '                '& ";" & datoPosicionCV.ToString
    '                archivoLogRelTransmision.WriteLine(logDescripcionRelTransmision)
    '            End If
    '        End If
    '    End If
    'End Sub
    Private Sub puertoSalida_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles puertoSensorSalida.DataReceived
        If puertoSensorSalida.ReadLine.Length > 1 Then
            Dim aux1 As String = ""
            Dim aux2 As Double = 0
            aux1 = puertoSensorSalida.ReadLine()
            aux2 = FiltroDatosSensorES(aux1)
            If aux2.Equals(100.0) Then 'si hay error en la lectura no hacer nada
                'datos no validos
                'KryptonLabel2.Text = "Error"
            Else
                If contadorS < 4 Then
                    'acumular
                    contadorS = contadorS + 1
                    vectorS(contadorS) = aux2
                Else
                    'media
                    For i = 0 To vectorS.Length - 1
                        mediaS = mediaS + vectorS(i)
                    Next
                    mediaS = mediaS / vectorS.Length
                    datoSensorSalida = aux2
                    mediaS = 0
                    contadorS = 0
                    vectorS(0) = Nothing
                    vectorS(1) = Nothing
                    vectorS(2) = Nothing
                    vectorS(3) = Nothing
                    vectorS(4) = Nothing
                End If
                'datoSensorSalida = aux2
                KryptonLabelSalida.Text = datoSensorSalida.ToString

                ' ToolStripLabelSensorSalida.Text = datoSensorSalida.ToString
            End If
        End If
    End Sub
    ''' <summary>
    ''' Recibe datos desde la placa que controla el cambio, de 0 a 100
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub puertoConexionCV_DataReceived()
        Dim aux1 As String = ""
        Dim aux2 As String = ""
        Dim sPatternActualEsIgual As String = "^\ Actual=\d{1,3}\.\d{1,2}$" 'para Actual=xx.xx,xxx.xx,xx.x,x.x,
        Dim sPatternDatoEsIgual As String = "^\Dato=\d{3}$" 'para Dato=xx.xx
        aux1 = puertoConexionCV.ReadLine() 'Leer y guardar la cadena en aux1
        If aux1.Length <> 0 Then
            aux2 = Replace(Trim(aux1), vbCr, "") 'Sacar espacios en blanco y substituir vbCr
            'logDescripcionCV = ""
            Select Case aux2.Length
                Case 8 ' Dato=xxx (espacion inicial 1)
                    If System.Text.RegularExpressions.Regex.IsMatch(aux2, sPatternDatoEsIgual) = True Then
                        datoUltimoCambioCV = Double.Parse(Mid(aux2, 6, 8), CultureInfo.InvariantCulture)
                        isOcupadoCV = True
                        '  logDescripcionCV += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & "Dato: " & aux2.ToString & "Longitud: " & aux2.Length.ToString & "Posicion: " & datoPosicionCV.ToString & "Ultima posicion: " & datoUltimoCambioCV.ToString & "Estado: " & isOcupadoCV.ToString
                    Else
                        '   logDescripcionCV += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & "No concuerda exp reg sPatternDatoEsIgual: " & aux2.ToString & "Longitud: " & aux2.Length.ToString & "Posicion: " & datoPosicionCV.ToString & "Ultima posicion: " & datoUltimoCambioCV.ToString & "Estado: " & isOcupadoCV.ToString
                        'MessageBox.Show("error exp reg 8" + aux2)
                    End If
                Case 11 'Moviendo...
                    'logDescripcionCV += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & "Moviendo: " & aux2.ToString & "Longitud: " & aux2.Length.ToString & "Posicion: " & datoPosicionCV.ToString & "Ultima posicion: " & datoUltimoCambioCV.ToString & "Ocupado: " & isOcupadoCV.ToString
                Case 12 To 14 ' Actual=x.xx/ Actual=xx.xx /xxx.xx(espacion inicial 1)
                    If System.Text.RegularExpressions.Regex.IsMatch(aux2, sPatternActualEsIgual) = True Then
                        If aux2.Length = 12 Then
                            datoPosicionCV = Double.Parse(Mid(aux2, 9, 12), CultureInfo.InvariantCulture)
                            'logDescripcionCV += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & "Dato: " & aux2.ToString & "Longitud: " & aux2.Length.ToString & "Posicion: " & datoPosicionCV.ToString & "Ultima posicion: " & datoUltimoCambioCV.ToString & "Estado: " & isOcupadoCV.ToString
                        ElseIf aux2.Length = 13 Then
                            datoPosicionCV = Double.Parse(Mid(aux2, 9, 13), CultureInfo.InvariantCulture)
                            'logDescripcionCV += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & "Dato: " & aux2.ToString & "Longitud: " & aux2.Length.ToString & "Posicion: " & datoPosicionCV.ToString & "Ultima posicion: " & datoUltimoCambioCV.ToString & "Estado: " & isOcupadoCV.ToString
                        Else
                            datoPosicionCV = Double.Parse(Mid(aux2, 9, 14), CultureInfo.InvariantCulture)
                            ' logDescripcionCV += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & "Dato: " & aux2.ToString & "Longitud: " & aux2.Length.ToString & "Posicion: " & datoPosicionCV.ToString & "Ultima posicion: " & datoUltimoCambioCV.ToString & "Estado: " & isOcupadoCV.ToString
                        End If
                        isOcupadoCV = False
                    Else
                        ' logDescripcionCV += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & "No concuerda con exp reg sPatternActualEsIgual : " & aux2.ToString & "Longitud: " & aux2.Length.ToString & "Posicion: " & datoPosicionCV.ToString & "Ultima posicion: " & datoUltimoCambioCV.ToString & "Estado: " & isOcupadoCV.ToString
                    End If
                    'logDescripcionCV += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & "No concuerda con ninguna longitud: " & aux2 & "Longitud: " & aux2.Length.ToString & "Posicion: " & datoPosicionCV.ToString & "Ultima posicion: " & datoUltimoCambioCV.ToString & "Estado: " & isOcupadoCV.ToString
            End Select

            'logDescripcionCV += DateTime.Now.ToString("dd-MM-yyyy hh:mm:ss") & "," & aux2.ToString & "," & datoSensorSalida.ToString & "," & CalculoRelacionDeTransmisionEnSal(aux2, datoSensorSalida).ToString
            'archivoLogCV.WriteLine(logDescripcionCV)
        End If
        'KryptonLabelEntrada.Text = datoPosicionCV.ToString
        'KryptonLabelSalida.Text = datoUltimoCambioCV.ToString
        'KryptonLabel3.Text = isOcupadoCV.ToString
        'Debug.WriteLine("---->>Bruto " + aux1 + " " + aux1.Length.ToString)
        'Debug.WriteLine("---->>Datos " + aux2 + " " + aux2.Length.ToString)
    End Sub
    ''' <summary>
    ''' Calcula la diferencia en porcentaje de dos numeros
    ''' Ejemplo: Inicial=100, Final=150, resultado=50 diferencia positivo
    ''' Ejemplo: Inicial=150.0, Final=100.0, resultado=-33.33 diferencia negativo
    ''' </summary>
    ''' <param name="numeroInicial"></param>
    ''' <param name="numeroFinal"></param>
    ''' <param name="nroDecimales"> Redondear un numero de decimales</param>
    ''' <returns>El valor en porcentaje de la diferencia de los dos numeros</returns>
    ''' <remarks></remarks>
    Shared Function DifPorcentajeDosNumeros(ByVal numeroInicial As Double, ByVal numeroFinal As Double, ByVal nroDecimales As Integer) As Double
        Dim resultado As Double = 0
        'dividir el valor nuevo entre el antiguo y multiplicar por 100,mult *100, restar -100
        'si el resultado es positivo es un porcentaje de aumento, si es negativo reducción.
        resultado = Math.Round((((numeroFinal / numeroInicial) * 100) - 100), nroDecimales)
        If resultado < 0 Then
            resultado = resultado * -1
        End If
        Return resultado
    End Function
#End Region
#Region "Caclculo de distancias de lat long"
    'sumar o restar distancias a lat, lon especificando el bearing(rumbo)
    'entrada bearing o rumbo, lat long que luego seran transformadas a distancias angulares
    'salida x,y con la distancia adicionada o substraida
    Public Shared Function CalculateDerivedPosition(ByVal LatOrigen As DotSpatial.Positioning.Latitude, ByVal LonOrigen As DotSpatial.Positioning.Longitude, ByVal rango As Double, ByVal rumbo As Azimuth) As DotSpatial.Positioning.CartesianPoint
        Dim angularLat As Double = LatOrigen.ToRadians
        Dim angularLon As Double = LonOrigen.ToRadians
        Dim angularDistance As Double = rango / 6378137.0 'radio de la tierra en wgs84
        Dim rumbo90, rumbo270, rumbo180 As Azimuth
        '  'Dim LatLonDoubleDer As Double()
        '  Dim LatLonDer As DotSpatial.Topology.Coordinate
        ' Dim LatLonIzq As DotSpatial.Topology.Coordinate
        rumbo90 = rumbo.Add(90) 'lado derecho sin restar distancia tractor sembradora
        rumbo270 = rumbo.Add(270) 'lado izq sin restar distancia tractor sembradora
        rumbo180 = rumbo.Add(180) 'rumbo final para restar ditancia
        'rumbo180 = rumbo.sub(180)  'para restar lado izq y der hacia atras por la diferencia de la sembradora
        'lado derecho
        '  LatLonDer = calculoLatLongDistancia(angularLat, angularLon, angularDistance, rumbo90.ToRadians)
        'lado izq
        '  LatLonIzq = calculoLatLongDistancia(angularLat, angularLon, angularDistance, rumbo270.ToRadians)
        'ahora se debe restar la distancia del lado izq y lado derecho ya que el gps esta en el techo y la sembradora atras
        'a unos 3 metros aproximadamente
        '  Dim LatLonDerFinal As DotSpatial.Topology.Coordinate
        '    Dim LatLonIzqFinal As DotSpatial.Topology.Coordinate
        'resultado ya restado del lado derecho
        '  LatLonDerFinal = calculoLatLongDistancia(LatLonDer.Y, LatLonDer.X, angularDistance, rumbo180.ToRadians)
        'resultado ya restado del lado izq
        '  LatLonIzqFinal = calculoLatLongDistancia(LatLonIzq.Y, LatLonIzq.X, angularDistance, rumbo180.ToRadians)

        Dim resultadoPunto As CartesianPoint
        'resultadoPunto = Distance.Parse(lon * 57.2957795)
        'LatOrigen.Parse(LatLonDerFinal.Y*57.2957795)	Para transformar radianes a grados decimales y parsear el resultado como une coordenada

        Return resultadoPunto
    End Function
    Public Shared Function calculoLatLongDistancia(ByVal LatOrigen As DotSpatial.Positioning.Latitude, ByVal LonOrigen As DotSpatial.Positioning.Longitude, ByVal distancia As Double, ByVal rumboOrigen As Azimuth, ByVal direccion As Double) As DotSpatial.Topology.Coordinate
        'permite hacer el calculo matematico de la distancia angular teniendo como entrada lat. lon. rumbo. rango
        'devuelve lat lon en formato de radianes (tipo double)
        'Transformaciones
        Dim angularLat As Double = LatOrigen.ToRadians
        Dim angularLon As Double = LonOrigen.ToRadians
        Dim angularDistancia As Double = distancia / 6378137.0 'radio de la tierra en wgs84
        Dim rumbo As Azimuth = rumboOrigen.Add(direccion)
        Dim cursoEnRadianes As Azimuth = rumbo.ToRadians

        Dim lat As Double = Math.Asin(Math.Sin(angularLat) * Math.Cos(angularDistancia) + Math.Cos(angularLat) * Math.Sin(angularDistancia) * Math.Cos(cursoEnRadianes))
        Dim dlon As Double = Math.Atan2(Math.Sin(cursoEnRadianes) * Math.Sin(angularDistancia) * Math.Cos(angularLat), Math.Cos(angularDistancia) - Math.Sin(angularLat) * Math.Sin(lat))
        Dim lon As Double = ((angularLon + dlon + Math.PI) Mod (2 * Math.PI)) - Math.PI
        Dim coordenadas As New Coordinate
        coordenadas.Y = lat
        coordenadas.X = lon
        Return coordenadas
    End Function

#End Region
    Private Sub nmeaInterpreter1_DateTimeChanged(ByVal sender As Object, ByVal e As DateTimeEventArgs) Handles NmeaInterpreter1.DateTimeChanged
        BeginInvoke(New EventHandler(Of DateTimeEventArgs)(AddressOf DateTimeChanged), sender, e)
    End Sub
    Private Sub DateTimeChanged(ByVal sender As Object, ByVal e As DateTimeEventArgs)
        'dateTimeTextBox.Text = e.DateTime.ToShortDateString() + " " + e.DateTime.ToLongTimeString()
        'utcDateTimeTextBox.Text = e.DateTime.ToUniversalTime().ToString("R")
    End Sub
    'Private Sub nmeaInterpreter1_SentenceReceived(ByVal sender As Object, ByVal e As NmeaSentenceEventArgs) Handles NmeaInterpreter1.SentenceReceived
    '    BeginInvoke(New EventHandler(Of NmeaSentenceEventArgs)(AddressOf SentenceReceived), sender, e)
    'End Sub

    'Private Sub SentenceReceived(ByVal sender As Object, ByVal e As NmeaSentenceEventArgs)
    '    'If sentenceListBox.Items.Count >= 100 Then
    '    '    sentenceListBox.Items.RemoveAt(0)
    '    'End If
    '    'sentenceListBox.Items.Add(e.Sentence.ToString())
    '    'sentenceListBox.SelectedIndex = sentenceListBox.Items.Count - 1
    '    'statusLabel.Text = "Recibiendo datos del GPS."
    'End Sub

#End Region
#Region " Funciones para el Log "
    Function createLog() As Boolean
        ' devuelve falso si ocuurre algun problema
        ' verdadero si salio todo bien
        Dim fechahora As String = DateTime.Now.ToString("dd-MM-yyyy-hh-mm-ss")
        fechahora = fechahora.Trim
        fechahora = Replace(fechahora, " ", "")
        'Label2.Text = fechahora
        'MessageBox.Show("Log " + fechahora)
        Try
            'Log Aplicacion
            nombreLogAplicacion = My.Application.Info.DirectoryPath & "\" & "Aplicacion_" & fechahora & ".txt"
            archivoLogAplicacion = My.Computer.FileSystem.OpenTextFileWriter(nombreLogAplicacion, False)
            archivoLogAplicacion.WriteLine("Fec_aplic,Hora,Latitud,Longitud,Rumbo,VRT,DosisP,DosisA,Velocidad,Ancho_lab,PcambioCalculado,RotacionSalida,PosicionCambio,ultimaPosicionCambio,ultimaDosisObjetivo")
            'Log Relacion de transmision
            'nombreLogCV = My.Application.Info.DirectoryPath & "\" & "RT_" & fechahora & ".txt"
            'archivoLogCV = My.Computer.FileSystem.OpenTextFileWriter(nombreLogCV, False)
            'archivoLogCV.WriteLine("Log de comportamiento CV")
            flagLog = True
            'Log Fuera del mapa
            nombreLogFueraDelMapa = My.Application.Info.DirectoryPath & "\" & "FueraDelMapa_" & fechahora & ".txt"
            archivoLogFueraDelMapa = My.Computer.FileSystem.OpenTextFileWriter(nombreLogFueraDelMapa, False)
            archivoLogFueraDelMapa.WriteLine("Fec_aplic,Hora,Latitud,Longitud,Rumbo,Velocidad")
            flagLog = True
            'Log Aplicacion Dosis Fija
            nombreLogAplicacionDF = My.Application.Info.DirectoryPath & "\" & "DosisFija_" & fechahora & ".txt"
            archivoLogAplicacionDF = My.Computer.FileSystem.OpenTextFileWriter(nombreLogAplicacionDF, False)
            archivoLogAplicacionDF.WriteLine("Fec_aplic,Hora,Latitud,Longitud,Rumbo,VRT,DosisP,DosisA,Velocidad,Ancho_lab,RotacionSalida,PosicionCambio")

            Return False
        Catch ex As Exception
            Return True
        End Try

    End Function
    Function closeLog() As Boolean
        ' devuelve falso si ocuurre algun problema
        ' verdadero si salio todo bien
        Try
            archivoLogAplicacion.Close()
            'archivoLogCV.Close()
            archivoLogFueraDelMapa.Close()
            archivoLogAplicacionDF.Close()
            'Console.WriteLine(My.Computer.FileSystem.ReadAllText(nombreLogAplicacion))
            flagLog = False
        Catch ex As Exception
            Return True
        End Try
        Return False

    End Function

#End Region

#Region "  Manejo de excepciones de la conexion  "

    Private Sub CurrentDomain_UnhandledException(ByVal sender As Object, ByVal e As UnhandledExceptionEventArgs)
        Dim ex As Exception = DirectCast(e.ExceptionObject, Exception)
        NotifyOfUnhandledException(ex)
    End Sub

    Private Sub Application_ThreadException(ByVal sender As Object, ByVal e As ThreadExceptionEventArgs)
        NotifyOfUnhandledException(e.Exception)
    End Sub
    'Manejo de excepciones del interprete
    'En caso de perdida de conexion
    Private Sub nmeaInterpreter1_ConnectionLost(ByVal sender As Object, ByVal e As ExceptionEventArgs) Handles NmeaInterpreter1.ExceptionOccurred
        BeginInvoke(New EventHandler(AddressOf ConnectionLost), sender, e)
    End Sub
    Private Sub ConnectionLost(ByVal sender As Object, ByVal e As ExceptionEventArgs)
        MessageBox.Show("Intentando reconexion automatica", "Error de conexion")
        'Me.statusConexionLabel.Text = "Error de conexion, intentando reconexion"
    End Sub

    ''' Logs para unhandled exception y muestra un message box mostrando el error.
    Shared Sub NotifyOfUnhandledException(ByVal exception As Exception)
        Try
            ' Log the exception (and all of its inner exceptions)
            Dim innerException As Exception = exception
            While (Not (innerException) Is Nothing)
                Trace.TraceError(innerException.ToString)
                innerException = innerException.InnerException
            End While

            ' Stop the interpreter
            ' NmeaInterpreter1.Stop()
        Finally
            ' Display the error to the user
            MessageBox.Show( _
             "Un error inesperado ha ocurrido." & vbLf & vbLf & exception.GetType.ToString & ": " & exception.Message, _
             Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

#End Region
#Region "  funciones escritas utiles  "

    'Private Sub btnDisplayStateName_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
    '    If Map1.Layers.Count > 0 Then
    '        'declaro MapPolygonLayer
    '        Dim stateLayer As MapPolygonLayer
    '        'TypeCast  la primera capa de MapControl a MapPolygonLayer.
    '        'Las capas son 0 basada, por lo tanto, 0 se va a agarrar la primera capa de la MapControl
    '        stateLayer = CType(Map1.Layers(0), MapPolygonLayer)

    '        'Comprueba si el stateLayer posee una capa de polígonos o no
    '        If stateLayer Is Nothing Then
    '            MessageBox.Show("La capa no es una capa de polígonos.")
    '        Else
    '            'agregar StateName como etiquetas en el stateLayer
    '            '[STATE_NAME] es un atributo del ejemplo dado shapefile EE.UU. Estados.
    '            Map1.AddLabels(stateLayer, "[AMBIENTE]", New Font("Tahoma", 8.0), Color.Black)

    '        End If
    '    Else
    '        MessageBox.Show("Por favor, añada una capa al mapa.")
    '    End If

    'End Sub

    'Private Sub btnFilterByStateName_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
    '    If Map1.Layers.Count > 0 Then
    '        'declaro MapPolygonLayer
    '        Dim stateLayer As MapPolygonLayer
    '        'TypeCast  la primera capa de MapControl a MapPolygonLayer.
    '        'Las capas son 0 basada, por lo tanto, 0 se va a agarrar la primera capa de la MapControl
    '        stateLayer = TryCast(Map1.Layers(0), MapPolygonLayer)
    '        'Comprueba si el stateLayer posee una capa de polígonos o no
    '        If stateLayer Is Nothing Then
    '            MessageBox.Show("La capa no es una capa de polígonos.")
    '        Else
    '            'SelectByAttribute método se utiliza para implementar las operaciones de filtrado.
    '            'En este ejemplo, se utiliza STATE_NAME implementar la operación de filtro
    '            'Podemos ver la IdhoSate en el mapa
    '            stateLayer.SelectByAttribute("[AMBIENTE] = 'Idaho'")
    '        End If
    '    Else
    '        MessageBox.Show("Por favor, añada una capa al mapa.")
    '    End If

    'End Sub


    'Private Sub btnRandomColors_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
    '    'comprobar el número de capas de control del mapa
    '    If Map1.Layers.Count > 0 Then
    '        'Declaro el mapa MapPolygonLayer
    '        Dim stateLayer As MapPolygonLayer
    '        'tipo emitido por el FirstLayer de MapControl a MapPolygonLayer
    '        stateLayer = CType(Map1.Layers(0), MapPolygonLayer)
    '        'Compruebe la MapPolygonLayer (Asegúrese de que tiene una capa de polígonos)
    '        If stateLayer Is Nothing Then
    '            MessageBox.Show("La capa no es una capa de polígonos.")
    '        Else
    '            'Crear un nuevo PolygonScheme
    '            Dim scheme As New PolygonScheme
    '            'Ajuste el ClassificationType para la PolygonScheme vía EditotSettings
    '            scheme.EditorSettings.ClassificationType = ClassificationType.UniqueValues
    '            'Establecer el nombre del campo UniqueValue
    '            'Aquí STATE_NAME sería el campo de valor único
    '            scheme.EditorSettings.FieldName = "AMBIENTE"
    '            'crear categorías en el esquema basado en la tabla de atributos y el nombre del campo
    '            'En este caso es el nombre del campo STATE_NAME
    '            scheme.CreateCategories(stateLayer.DataSet.DataTable)
    '            'Establecer el esquema de la simbología stateLayer
    '            stateLayer.Symbology = scheme
    '        End If
    '    Else
    '        MessageBox.Show("Por favor, añada una capa al mapa.")
    '    End If

    'End Sub





    'Private Sub btnViewAttributes_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
    '    'Declaro datatable
    '    Dim dt As DataTable
    '    If Map1.Layers.Count > 0 Then
    '        Dim stateLayer As MapPolygonLayer
    '        stateLayer = CType(Map1.Layers(0), MapPolygonLayer)
    '        If stateLayer Is Nothing Then
    '            MessageBox.Show("Esta capa no es un poligono.")
    '        Else
    '            'Obtener tabla de atributos del shapefile a nuestra tabla de datos dt
    '            dt = stateLayer.DataSet.DataTable
    '            'Ajuste la fuente de datos de datagridview DataTable dt
    '            'dgvAttributeTable.DataSource = dt
    '        End If
    '    Else
    '        MessageBox.Show("Por favor, añada una capa al mapa.")
    '    End If

    'End Sub

    'funcion en el cual se ingresa las coordenas del mapa y se obtiene el indice .dbf
    Function CoordinatesInShapefile(ByVal aX As Double, ByVal aY As Double) As Integer

        Dim lCoordinate As New DotSpatial.Topology.Coordinate(aX, aY)


        Dim fs As IFeatureSet = Map1.Layers(0).DataSet
        Dim lShapeIndices = fs.ShapeIndices
        If pLastCoordinateIndex > -1 AndAlso lShapeIndices(pLastCoordinateIndex).Intersects(lCoordinate) Then
            Return pLastCoordinateIndex
        End If

        Dim lIndex As Integer = 0
        For Each lShapeRange As DotSpatial.Data.ShapeRange In fs.ShapeIndices
            If pointInPolygon(lShapeRange, lCoordinate) Then
                pLastCoordinateIndex = lIndex
                Return lIndex
            End If
            lIndex += 1
        Next





        Return (-1)
    End Function
    'este algoritmo obtine un punto en el poligono de una coordenada dada
    Public Function pointInPolygon(ByVal shape As ShapeRange, ByVal coord As Coordinate) As Boolean
        Dim polysides As Integer
        Dim polyX(), polyY(), x, y As Double
        Dim part As PartRange
        Dim vert As Vertex
        x = coord.X
        y = coord.Y

        polysides = 0
        For Each part In shape.Parts
            polysides = polysides + part.NumVertices
        Next
        Dim i As Integer
        Dim j As Integer = polysides - 1
        ReDim polyX(polysides)
        ReDim polyY(polysides)

        i = 0
        Dim oddNodes As Boolean = False
        Dim nodes As Integer

        If shape.Extent.MaxY >= y And shape.Extent.MinY <= y Then
            For Each part In shape.Parts
                For Each vert In part
                    polyX(i) = vert.X
                    polyY(i) = vert.Y
                    i = i + 1
                Next
            Next

            nodes = 0
            For i = 0 To polysides - 1

                If ((polyY(i) < y And polyY(j) >= y) Or (polyY(j) < y And polyY(i) >= y)) And (polyX(i) <= x Or polyX(j) <= x) Then
                    If (polyX(i) + (y - polyY(i)) / (polyY(j) - polyY(i)) * (polyX(j) - polyX(i)) < x) Then
                        nodes = nodes + 1
                    End If
                End If
                j = i
            Next
            If nodes Mod 2 <> 0 Then
                oddNodes = True
            End If
        End If
        Return oddNodes
    End Function

#End Region
#Region "  Manejo del Map1 shapeFile "
    'abre el mapa
    Private Sub AbrirMapaToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AbrirMapaToolStripMenuItem.Click
        'AddLayer() metodo que es usado para aderir el shapefile al MapControl

        If Map1.Layers.Count = 0 Then


            Dim colorMapa As PolygonSymbolizer = New PolygonSymbolizer(Color.LightGreen)
            colorMapa.OutlineSymbolizer = New LineSymbolizer(Color.Black, 1)
            Map1.AddLayer()

            If Map1.Layers.Count > 0 Then
                fl = Map1.GetFeatureLayers(0)
                fl.Symbolizer = colorMapa
            End If
            

            flagCargarMapa = 1
            deteccionAutoButton1.Enabled = True
            statusConexionLabel.Text = "Deteccion automatica habilitada"
            ButtonConectarCV.Enabled = True
            CaracteristicaToolStripButton.PerformClick()
        Else
            MessageBox.Show("Lo sentimos, ya se cargo el mapa. Si desea cargar un nuevo mapa cierre el actual y luego vuelva a cargar")
        End If
        '  NombreArchivoKryptonLabeL.Text = "Nombre del Archivo: " & Map1.Layers.


    End Sub
    'cierra el mapa 
    Private Sub CerrarMapaToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CerrarMapaToolStripMenuItem.Click
        Map1.ClearLayers()
        flagCargarMapa = 0
        deteccionAutoButton1.Enabled = False
        TrabajarButton1.Enabled = False
        statusConexionLabel.Text = "El mapa se ha cerrado"
    End Sub
    'manejo de zoon y extencion del mapa

    Private Sub zoonMas_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton4.Click
        Map1.ZoomIn()
    End Sub

    Private Sub zoonMenos_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton3.Click
        Map1.ZoomOut()
    End Sub

    Private Sub zoonExtender_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ToolStripButton2.Click
        Map1.ZoomToMaxExtent()
    End Sub

    Private Sub clearMapa_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Map1.Layers.Clear()
    End Sub


#End Region




    'Private Sub MainForm_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed
    '    'sw.Stop()
    '    'End

    'End Sub


    ' Estructura POINTAPI  
    Private Sub MainForm_FormClosing( _
                ByVal sender As Object, ByVal e As FormClosingEventArgs) _
                Handles Me.FormClosing
        ' Mostrar un mensaje de porqué se está cerrando
        'MessageBox.Show(e.CloseReason.ToString)
        Map1.Dispose()
        Legend1.Dispose()
        GlControl1.Dispose()
        NmeaInterpreter1.Dispose()
        If puertoConexionCV IsNot Nothing Then
            puertoConexionCV.Dispose()
            puertoConexionCV.Close()
        End If
        If flagLog Then
            closeLog()
        End If

        'System.Threading.ThreadAbortException' en mscorlib.dll 

        Try

        Catch ex As ThreadAbortException
            MessageBox.Show("mensaje de execpcion " & ex.Message)
        End Try


        ' Estos son los valores posibles
        Select Case e.CloseReason
            Case CloseReason.ApplicationExitCall
            Case CloseReason.FormOwnerClosing
            Case CloseReason.MdiFormClosing
            Case CloseReason.None
            Case CloseReason.TaskManagerClosing
            Case CloseReason.UserClosing
            Case CloseReason.WindowsShutDown
        End Select
    End Sub

    Private Sub MainForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        Dim resultado As Double
        'calibrar
        For i = 0 To 100 Step 1
            resultado = (My.MySettings.Default.ValorDeCalibracion * i) / 100
            'Debug.WriteLine("KgHa: " & resultado & " cambio: " & i)
            vectorCambio(100 - i) = Math.Round(resultado, 1)
        Next
        'defino el puntero en default para luego reutilizarlo
        Map1.FunctionMode = FunctionMode.None
        'deshabilitar botones trabajar y detectar antes de cargar el mapa
        TrabajarButton1.Enabled = False
        deteccionAutoButton1.Enabled = False
        pararTrabajoButton1.Enabled = False



    End Sub

    Public Sub Map1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Map1.Paint
        'Dim _GpsPos As Coordinate = myCoordenateGPS
        ''if gps is enabled continue
        'If gpsActivo <> False AndAlso _GpsPos IsNot Nothing Then
        '    'dibujar una elipse en la posición gps actual, utilizando el PaintEventArgs
        '    Dim g As Graphics = e.Graphics
        '    Dim pen As New Pen(Color.FromArgb(128, 255, 0, 0), 3)
        '    'convertir la posición gps para asignar píxeles
        '    Dim ptGPSinPixels As System.Drawing.Point = Map1.ProjToPixel(New DotSpatial.Topology.Coordinate(_GpsPos))
        '    g.DrawEllipse(pen, New Rectangle(ptGPSinPixels.X, ptGPSinPixels.Y, 5, 5))

        '    'Si se ha movido en el mapa se reaposiniona en la coordenada gps 
        '    'If Map1.ViewExtents.MaxX < _GpsPos.Y OrElse Map1.ViewExtents.MinX > _GpsPos.X OrElse Map1.ViewExtents.MaxY < _GpsPos.Y OrElse Map1.ViewExtents.MinY > _GpsPos.X Then
        '    '    Map1.ViewExtents.SetCenter(_GpsPos.X, _GpsPos.Y, Map1.ViewExtents.Width, Map1.ViewExtents.Height)
        '    'End If
        '    Map1.ResetBuffer()
        '    Map1.Invalidate()



        '    'Else
        '    '    ePaintEventArgs = e
        'End If

    End Sub
#Region "funciones para barra inferior y manejo del teclado, caracteristicas de suelo"
    'visualizacion de coordena del mapa, esta segun posicion pantalla
    Private Sub Map1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs)

        'obtengo las coordenas del pixel de la pantalla 
        'y luego lo conviento en coordenadas reales del mapa
        Dim coord As Coordinate = Map1.PixelToProj(e.Location)
        Dim sLong As String
        Dim slat As String

        sLong = coord.X.ToString()
        slat = coord.Y.ToString()
        'muestro en la detalleBarra 
        pocisionCursor.Text = "Lat: " & slat & " Long: " & sLong


    End Sub
    'para seleccionar una sub zona del mapa
    Private Sub SeleccionarToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SeleccionarToolStripMenuItem.Click
        If Map1.Layers.Count > 0 Then
            'pongo la funcion del puntero en default para luego reutilizarlo
            Map1.FunctionMode = FunctionMode.None
            'pongo la funcion select para selecionar el poligono en esa coordenada donde  cliqueo
            Map1.FunctionMode = FunctionMode.Select
        Else
            MessageBox.Show("Lo sentimos, no ha añadido el archivo .shp para realizar estar acción.")
        End If
    End Sub
    'para exploarar el mapa
    Private Sub ExploaraMapaToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExploaraMapaToolStripMenuItem.Click
        If Map1.Layers.Count > 0 Then
            'pongo la funcion del puntero en default para luego reutilizarlo
            Map1.FunctionMode = FunctionMode.None
            'pongo la funcion pan para explorar el mapa
            Map1.FunctionMode = FunctionMode.Pan
        Else
            MessageBox.Show("Lo sentimos, no ha añadido el archivo .shp para realizar estar acción.")
        End If
    End Sub
    'para visualizar los datos del mapa en una tabla
    Private Sub InforMapaToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles InforMapaToolStripMenuItem.Click
        If Map1.Layers.Count > 0 Then
            'pongo la funcion del puntero en default para luego reutilizarlo
            Map1.FunctionMode = FunctionMode.None
            'pongo la funcion info para obtener los atributos .dfb en esa coordenada donde cliqueo
            Map1.FunctionMode = FunctionMode.Info
        Else
            MessageBox.Show("Lo sentimos, no ha añadido el archivo .shp para realizar estar acción.")
        End If
    End Sub
    'desabilitar todas las funciones
    Private Sub DeshabilitarDetalleToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DeshabilitarDetalleToolStripMenuItem.Click
        If Map1.Layers.Count > 0 Then
            'pongo la funcion del puntero en default para luego reutilizarlo
            Map1.FunctionMode = FunctionMode.None

        Else
            MessageBox.Show("Lo sentimos, no ha añadido el archivo .shp para realizar estar acción.")
        End If
    End Sub

    ' manejo de funciones por teclado
    Private Sub MainForm_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown
        e.Handled = True

        Select Case e.KeyValue

            Case Keys.Left
                MessageBox.Show("Lo sentimos, no ha añadido el archivo .shp para realizar estar acción.")

                '            Case Keys.Enter
                '               MessageBox.Show("enter")

            Case Keys.Space
                MessageBox.Show("spacio")

                'Case Keys.Home

                '    'muestra la cabecera 
                '    kryptonInfoCabecera.Collapsed = False

                'Case Keys.PageUp
                '    'esconde la cabecera 
                '    kryptonInfoCabecera.Collapsed = True


            Case Keys.End

                'muestra la cabecera 
                kryptonAgrupacionTrabajo.Collapsed = False

            Case Keys.PageDown
                'esconde la cabecera 
                kryptonAgrupacionTrabajo.Collapsed = True
            Case Keys.Z
                Map1.ZoomIn()
            Case Keys.X
                Map1.ZoomOut()
            Case Keys.M
                If Opengl.flagMarcar Then
                    Opengl.flagMarcar = False
                    Opengl.flagMarcarFalse = False
                Else

                    Opengl.flagMarcar = True
                    Opengl.flagMarcarFalse = True
                End If
                'Case Keys.D1
                '   MessageBox.Show("1")



        End Select
    End Sub



    'visualizar el mapa segun sub zonas, esta la productivdad que posee
    Private Sub CaracteristicaToolStripButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CaracteristicaToolStripButton.Click
        'comprobar el número de capas de control del mapa
        If Map1.Layers.Count > 0 Then
            'Declaro el mapa MapPolygonLayer
            Dim stateLayer As MapPolygonLayer
            'tipo emitido por el FirstLayer de MapControl a MapPolygonLayer
            stateLayer = CType(Map1.Layers(0), MapPolygonLayer)
            'Compruebe la MapPolygonLayer (Asegúrese de que tiene una capa de polígonos)
            If stateLayer Is Nothing Then
                MessageBox.Show("La capa no es una capa de polígonos.")
            Else
                'Crear un nuevo PolygonScheme
                Dim scheme As New PolygonScheme
                'Ajuste el ClassificationType para la PolygonScheme vía EditotSettings
                scheme.EditorSettings.ClassificationType = ClassificationType.UniqueValues
                'Establecer el nombre del campo UniqueValue
                'Aquí STATE_NAME sería el campo de valor único
                scheme.EditorSettings.FieldName = My.MySettings.Default.sustituirDosisKgHa.ToString
                'crear categorías en el esquema basado en la tabla de atributos y el nombre del campo
                'En este caso es el nombre del campo STATE_NAME
                scheme.CreateCategories(stateLayer.DataSet.DataTable)
                'Establecer el esquema de la simbología stateLayer
                stateLayer.Symbology = scheme
            End If
        Else
            MessageBox.Show("Por favor, añada una capa al mapa.")
        End If
    End Sub
#End Region
#Region "Eventos Toolstrip"
    Private Sub InformacionDelDispositivoToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        If NmeaInterpreter1.IsRunning Then 'Controlar que se haya establecido la conexion
            CalibracionCV.TextBoxKgha.Text = NmeaInterpreter1.Device.Name
            'CalibracionCV.TextBoxRelTransmision.Text = NmeaInterpreter1.FixPrecisionEstimate
            CalibracionCV.Show()
        Else
            MessageBox.Show("Todavia no se ha establecido una conexion")
        End If
    End Sub
    'Configurar parametros de la aplicacion
    Private Sub ConfiguracionToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ConfiguracionToolStripMenuItem.Click
        ConfiguracionForm.Show()
    End Sub
    'Salir desde el toolstrip
    Private Sub SalirToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SalirToolStripMenuItem.Click
        'confirma la salida del sistema
        If NmeaInterpreter1.IsRunning Then 'Revisar si la conexion esta todavia abierta
            MessageBox.Show("La conexion continua abierta, cierrela si quiere salir del sistema")
        Else
            If (MessageBox.Show("Esta seguro que quiere salir del sistema?", "AgroControl", MessageBoxButtons.OKCancel) = DialogResult.OK) Then
                'Close() metodo para cerrar
                'Opengl.EliminarOpenGL() ' esto cerraria opengl pero crea un error

                If NmeaInterpreter1.Device IsNot Nothing Then
                    NmeaInterpreter1.Device.Close() 'cerrar la conexion antes de salir
                End If
                'sw.Start()
                Me.Close()
            End If
        End If
    End Sub
#End Region
#Region "botones para trabajar"
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrabajarButton1.Click
        If NmeaInterpreter1.IsRunning Then
            conectado = True
            If flagPausa = 0 Then
                NmeaInterpreter1.Pause()
                flagPausa = 1
            Else
                NmeaInterpreter1.Resume()
                flagPausa = 0
            End If
        Else
            NmeaInterpreter1.Start()
            conectado = True
        End If

    End Sub
    Private Sub pararTrabajoButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles pararTrabajoButton1.Click
        NmeaInterpreter1.Stop()
        deteccionAutoButton1.Enabled = True
        TrabajarButton1.Enabled = False
        pararTrabajoButton1.Enabled = False

        RealizarCambio("000")
        'Dim mes = New MessageBox


        System.Threading.Thread.Sleep(20000)
        MessageBox.Show("Trabajo Terminado")

    End Sub
#End Region
#Region "Metodos OpenGl"
    'funciones zoon
    Private Sub masOpengl_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles masOpengl.Click
        If Opengl.pers > 10.0R Then
            Opengl.pers -= 10.0R
        End If
    End Sub

    Private Sub menosOpenGl_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles menosOpenGl.Click
        If Opengl.pers < 175.0R Then
            Opengl.pers = (10.0R + Opengl.pers)
        End If
    End Sub
    'cambia la visualizacion en 2D y 3D
    Private Sub dimencionOpenGl_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles dimencionOpenGl.Click
        If Opengl.flagD = 3 Then

            Opengl.azimut = 89.9R
            Opengl.flagD = 2
            dimencionOpenGl.Text = "2D"
        Else
            Opengl.azimut = 20.0R
            Opengl.flagD = 3
            dimencionOpenGl.Text = "3D"
        End If
    End Sub
    'marca el recorrido activa y desactiva
    Private Sub marcarOpenGl_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles marcarOpenGl.Click
        If Opengl.flagMarcar Then
            Opengl.flagMarcar = False
            Opengl.flagMarcarFalse = False
        Else

            Opengl.flagMarcar = True
            Opengl.flagMarcarFalse = True
        End If
    End Sub
    'carga el loader donden prende la bandera a true comenzo a leer 
    Private Sub GlControl1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GlControl1.Load
        loader = True
        ClearColor(Color.Black)
        SetupViewport()
        sw.Start()
    End Sub
    'renderiza el tamano del bojeto controlgll donde se visualizara el grafico
    Private Sub GlControl1_Resize(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GlControl1.Resize

        If (Not loader) Then
            Return
        End If
        SetupViewport()
        GlControl1.Invalidate()
    End Sub
    'funcion que renderiza el tamanho del grafico opengl, segun sea el tamanho del monitor
    Private Sub SetupViewport()

        Dim w As Integer = GlControl1.Width
        Dim h As Integer = GlControl1.Height

        Dim AspectRadio As Double = w / h
        Viewport(0, 0, w, h)
        OpenTK.Graphics.OpenGL.GL.MatrixMode(OpenTK.Graphics.OpenGL.MatrixMode.Projection)
        LoadIdentity()

        Dim perspective As OpenTK.Matrix4 = OpenTK.Matrix4.CreatePerspectiveFieldOfView(((45.0F * System.Math.PI) / 180), AspectRadio + 0, 0.1F, 1000.0F)
        MultMatrix(perspective)
        'Perspective(45.0F, AspectRadio + 0, 0.1, 10000.0)
        OpenTK.Graphics.OpenGL.GL.MatrixMode(OpenTK.Graphics.OpenGL.MatrixMode.Modelview)

        LoadIdentity()
    End Sub

    'se da inicio a la grafica 
    Private Sub GlControl1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles GlControl1.Paint
        If (Not loader) Then
            Return
        End If
        Clear(ClearBufferMask.ColorBufferBit)
        Clear(ClearBufferMask.DepthBufferBit)


        Try
            Opengl.Inicializaciones()
            Opengl.BucleOpenGl()
        Catch ex As ThreadAbortException
            MessageBox.Show("mensaje de execpcion " & ex.Message)
        End Try

    End Sub
#End Region

    Private Sub statusConexionLabel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles statusConexionLabel.Click

    End Sub

    Private Sub KryptonButton1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles KryptonButton1.Click
        'DifPorcentajeDosNumeros(150.0, 100.0, 2)
        'puertoConexionCV.Write(KryptonTextBox1.Text, 0, 3)
        'cerrarConexionesCV()
        'RealizarCambio("010")
        puertoConexionCV.Close()
        ' MessageBox.Show(TablaDosisPorcentajeCv(KryptonTextBox1.Text))
        'RealizarCambio(TablaDosisPorcentajeCv(KryptonTextBox1.Text))


    End Sub
    Private Sub cerrarConexionesCV()
        'puertoConexionCV.Close()
        puertoSensorEntrada.Close()
        puertoSensorSalida.Close()
    End Sub

    Private Sub CalibracionToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CalibracionToolStripMenuItem.Click
        CalibracionCV.Show()
    End Sub

    Private Sub ButtonConectarComs_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonConectarCV.Click
        'datosSensorSalida()
        'FiltroDatosSensorES("                15.88 rps         ")
        'CalculoCambioCaja(224.81625594466061, 2.7)
        'DosisActual(2.7)
        'ConsultarEstadoCV()
        'createLog()
        Try

            If (puertoConexionCV IsNot Nothing) Then
                puertoConexionCV.Close()
            End If

            puertoConexionCV = My.Computer.Ports.OpenSerialPort(My.MySettings.Default.puertoConexionCV.ToString)
            'puertoSensorSalida = My.Computer.Ports.OpenSerialPort(My.MySettings.Default.puertoSensorSalida.ToString)
            'puertoConexionCV.ReadTimeout = 10000
            'puertoSensorSalida.ReadTimeout = 10000
            MessageBox.Show("Caja conectada en puerto: " & My.MySettings.Default.puertoConexionCV.ToString)
        Catch ex As Exception
            MessageBox.Show("Error al abrir el puerto serial: " & ex.Message, "Error de conexion")
            'retorna a la pantalla inicial si existe una excepcion  
            Return
        Finally

            'If puertoConexionCV Is Nothing Or puertoSensorSalida Is Nothing Then

            '    'puertoConexionCV.Close()
            '    'puertoSensorSalida.Close()
            'End If
            
        End Try
    End Sub
End Class
